package com.platform.dao;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.hibernate.criterion.Order;

import com.platform.dao.base.HibernateDAO;
import com.platform.internal.OrderList;
import com.platform.utils.ReflectionUtils;

/**
 * 一个HibernateDAO的包装类，具体操作由HibernateDAO来执行，
 * 这个类的目的是为了解除Hibernate，Spring和DAO之间的耦合，
 * 方便以后DAO实现的替换.
 * 
 * TODO：我不确定有没有这个必要... By: WF
 * 
 * @author WANG Fei
 *
 * @param <T>  Entity类型
 * @param <PK> Entity主键类型
 */
public class BaseDAO<T, PK extends Serializable> {

	private HibernateDAO<T, PK> referenceDAO;
	private Class<T> entityClass;

	/**
	 * 用于Dao层子类的构造函数. 通过子类的泛型定义取得对象类型Class. 
	 * eg. public class UserDao extends BaseDAO<User, Long>{ }
	 */
	public BaseDAO() {
		this.entityClass = ReflectionUtils.getSuperClassGenricType(this.getClass());
	}

	/**
	 * 用于省略Dao层, Service层直接使用通用BaseDAO的构造函数. 在构造函数中定义对象类型Class.
	 */
	public BaseDAO(final Class<T> entityClass) {
		this.entityClass = entityClass;
	}
	
	private HibernateDAO<T, PK> getReferenceDAO() {
    	return this.referenceDAO;
    }

	/**
	 * 设置具体执行DAO操作的DAO对象
	 * 
	 * @param referenceDAO
	 */
	public void setReferenceDAO(HibernateDAO<T, PK> referenceDAO) {
    	this.referenceDAO = referenceDAO;
    	
    	this.referenceDAO.setEntityClass(this.entityClass);
    }
	
	/**
	 * 初始化对象. 使用load()方法得到的仅是对象Proxy, 在传到View层前需要进行初始化. 如果传入entity,
	 * 则只初始化entity的直接属性,但不会初始化延迟加载的关联集合和属性. 如需初始化关联属性,需执行:
	 * Hibernate.initialize(user.getRoles())，初始化User的直接属性和关联集合.
	 * Hibernate.initialize
	 * (user.getDescription())，初始化User的直接属性和延迟加载的Description属性.
	 */
	public void initProxyObject(final Object proxy) {
		this.getReferenceDAO().initProxyObject(proxy);
	}

	/**
	 * Flush当前Session.
	 */
	public void flush() {
		this.getReferenceDAO().flush();
	}

	/**
	 * 判断对象的属性值在数据库内是否唯一.
	 * 
	 * 在修改对象的情景下,如果属性新修改的值(value)等于属性原来的值(orgValue)则不作比较.
	 */
	public boolean isPropertyUnique(final String propertyName, final Object newValue,
	        final Object oldValue) {
		return this.getReferenceDAO().isPropertyUnique(propertyName, newValue, oldValue);
	}
	
	/**
	 * 保存新增或修改的对象.
	 */
	public void save(final T entity) {
		this.getReferenceDAO().save(entity);
	}

	/**
	 * 删除对象.
	 * 
	 * @param entity
	 *            对象必须是session中的对象或含id属性的transient对象.
	 */
	public void delete(final T entity) {
		this.getReferenceDAO().delete(entity);
	}

	/**
	 * 按id删除对象.
	 */
	public void delete(final PK id) {
		this.getReferenceDAO().delete(id);
	}

	/**
	 * 获取全部对象.
	 */
	public List<T> findAll() {
		return this.getReferenceDAO().findAll();
	}
	
	/**
	 * 按id获取对象.
	 */
	public T findById(final PK id) {
		return this.getReferenceDAO().findById(id);
	}

	/**
	 * 按属性查找对象列表, 匹配方式为相等.
	 */
    public List<T> findBy(final String propertyName, final Object value) {
    	return this.getReferenceDAO().findBy(propertyName, value, (OrderList)null);
	}
	
	/**
	 * 按属性查找对象列表, 匹配方式为相等.
	 */
    public List<T> findBy(final String propertyName, final Object value, final Order order) {
		return this.getReferenceDAO().findBy(propertyName, value, new OrderList(order));
	}
    
	/**
	 * 按属性查找对象列表, 匹配方式为相等.
	 */
    public List<T> findBy(final String propertyName, final Object value, final OrderList orderList) {
		return this.getReferenceDAO().findBy(propertyName, value, orderList);
	}
    
    
	
	/**
	 * 按属性查找唯一对象, 匹配方式为相等.
	 */
    public T findUniqueBy(final String propertyName, final Object value) {
		return this.getReferenceDAO().findUniqueBy(propertyName, value);
	}

	/**
	 * 按QL查询唯一对象.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
    public <X> X findUnique(final String ql, final Object... values) {
		return this.getReferenceDAO().findUnique(ql, values);
	}
	

	/**
	 * 按QL查询唯一对象.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
    public <X> X findUnique(final String ql, final Map<String, ?> values) {
		return this.getReferenceDAO().findUnique(ql, values);
	}
	
	/**
	 * 按QL查询对象列表.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 */
    public <X> List<X> find(final String ql, final Object... values) {
		return this.getReferenceDAO().find(ql, values);
	}

	/**
	 * 按QL查询对象列表.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 */
    public <X> List<X> find(final String ql, final Map<String, ?> values) {
		return this.getReferenceDAO().find(ql, values);
	}
	
	/**
	 * 执行QL进行批量修改/删除操作.
	 * 
	 * @param values
	 *            数量可变的参数,按顺序绑定.
	 * @return 更新记录数.
	 */
	public int batchExecute(final String ql, final Object... values) {
		return this.getReferenceDAO().batchExecute(ql, values);
	}

	/**
	 * 执行QL进行批量修改/删除操作.
	 * 
	 * @param values
	 *            命名参数,按名称绑定.
	 * @return 更新记录数.
	 */
	public int batchExecute(final String ql, final Map<String, ?> values) {
		return this.getReferenceDAO().batchExecute(ql, values);
	}
}
